package com.huatai.datacenter.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.freakchick.orange.SqlMeta;
import com.huatai.common.api.R;
import com.huatai.datacenter.entity.ApiEntity;
import com.huatai.datacenter.entity.DataSourceEntity;
import com.huatai.datacenter.entity.RequestLogEntity;
import com.huatai.datacenter.entity.dto.EncryDto;
import com.huatai.datacenter.service.ApiService;
import com.huatai.datacenter.service.DataSourceService;
import com.huatai.datacenter.service.DesensitizationRuleService;
import com.huatai.datacenter.service.RequestService;
import com.huatai.datacenter.utils.JDBCUtil;
import com.huatai.datacenter.utils.SqlEngineUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.sql.Array;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Lion
 * @date 2023/4/18  9:26
 */
@Component
public class ApiInterceptor implements HandlerInterceptor {
	@Autowired
	private ApiService apiService;

	@Autowired
	private DataSourceService dataSourceService;

	@Autowired
	private RequestService requestService;

	@Autowired
	private DesensitizationRuleService desensitizationRuleService;

	/**
	 * @param request
	 * @param arg1
	 * @param arg2
	 * @param arg3
	 * @return void
	 * @author Lion
	 * @description 整个请求处理完毕后回调方法，即在视图渲染完毕时回调，
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {

	}

	/**
	 * @param request
	 * @param arg1
	 * @param arg2
	 * @param arg3
	 * @return void
	 * @author Lion
	 * @description 后处理回调方法，实现处理器的后处理（但在试图渲染之前），此时可以通过modelAndView（模型和视图对象）对模型数据进行处理或对试图进行处理
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {

	}

	/**
	 * @param request
	 * @param response
	 * @param arg2
	 * @return boolean
	 * @author Lion
	 * @description 预处理回调方法，实现处理器的预处理，第三个参数为响应的处理器
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws IOException {

		String servletPath = request.getServletPath();
		servletPath = servletPath.substring(10);

		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		// 跨域设置
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Credentials", "true");
		response.setHeader("Access-Control-Allow-Headers", "Authorization");
		response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");

		//ServletOutputStream out = null;

		try {
			//out = response.getWriter();
			R responseMessage = process(servletPath, request, response);
			response.getWriter().print(JSON.toJSONString(responseMessage));//append(JSON.toJSONString(responseMessage));
			return false;
		} catch (IOException | SQLException | ServletException e) {
			e.printStackTrace();
			response.sendError(500);
			return false;
		} finally {
			if (response.getWriter() != null)
				response.getWriter().close();
		}
	}

	/**
	 * @author Lion
	 * @description 判断有无权限  有则返回数据  无则退出
	 * @param path
	 * @param request
	 * @param response
	 * @return com.huatai.common.api.R
	 */
	public R process(String path, HttpServletRequest request, HttpServletResponse response) throws SQLException, ServletException, IOException {

		int size = 0;
		ApiEntity apiEntity = apiService.getConfig(path);
		if (apiEntity == null) {
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
			requestService.saveLog(path,"error","Api not exists","",apiEntity.getApiName(),size);
			return R.fail("Api not exists");
		}

		//判断传入appkey与数据库中保存的是否一致，如果一致则继续执行，反之则返回该服务对象无访问该API的权限 SC_FORBIDDEN
		JSONObject bodyMap = getJSON(request);
		if (bodyMap == null) {
			response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
			requestService.saveLog(path,"error","未携带参数appKey",bodyMap.toString(),apiEntity.getApiName(),size);
			return R.fail("请携带参数appKey");
		}
		String appKey = bodyMap.getString("appKey");
		if (StringUtils.isBlank(appKey)) {
			response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
			requestService.saveLog(path,"error","参数值为空",bodyMap.toString(),apiEntity.getApiName(),size);
			return R.fail("请携带参数：appKey");
		}

		if (!apiEntity.getAppKey().contains(appKey)) {
			response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
			requestService.saveLog(path,"error","无权访问",bodyMap.toString(),apiEntity.getApiName(),size);
			return R.fail("无权访问");
		}

		DataSourceEntity dataSource = dataSourceService.detail(apiEntity.getDatasourceId());
		if (dataSource == null) {
			response.setStatus(500);
			requestService.saveLog(path,"error","服务端错误：Datasource not exists!",bodyMap.toString(),apiEntity.getApiName(),size);
			return R.fail("Datasource not exists!");
		}

		Map<String, Object> sqlParam = apiService.getSqlParam(request, apiEntity);
		String sql = apiEntity.getSqlData();
		//将参数加载到SQL语句中
		//根据在ApiConfig中的参数名称，在body参数中获取对应的参数值
		SqlMeta sqlMeta = SqlEngineUtil.getEngine().parse(sql, sqlParam);
		R responseMessage = JDBCUtil.executeSql(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());
		Object data = responseMessage.getData();
		if (data instanceof List){
			List<?> ls = (List<?>) data;
			size = ls.size();
		}
		Long requrtId = requestService.saveLog(path,"success","请求成功",bodyMap.toString(),apiEntity.getApiName(),size);


		//添加数据脱敏 数据加密逻辑
		String desensitizationId = apiEntity.getDesensitizationId();//获取脱敏规则id
		JSONArray desenIds = new JSONArray();
		if (StringUtils.isNotBlank(desensitizationId)) {
			desenIds.add(Long.parseLong(desensitizationId));
			JSONObject key = new JSONObject();
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("key",key);
			jsonObject.put("desenIds",desenIds);
			jsonObject.put("data",data.toString());
			JSONArray desenId = jsonObject.getJSONArray("desenIds");
			Long[] ids = new Long[desenId.size()];
			Long[] longs = desenId.toArray(ids);
			EncryDto encryDto = desensitizationRuleService.desensitizationDataCopy(jsonObject.getJSONObject("key"), longs, jsonObject.getString("data"),requrtId);
			return R.data(encryDto);
		}else {
			return responseMessage;
		}
	}

	/**
	 * @author Lion
	 * @description 封装json
	 * @param  * @param request
	 * @return com.alibaba.fastjson.JSONObject
	 */
	public JSONObject getJSON(HttpServletRequest request) throws ServletException, IOException {

		BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
		StringBuilder responseStrBuilder = new StringBuilder();
		String inputStr;
		while ((inputStr = streamReader.readLine()) != null) {
			responseStrBuilder.append(inputStr);
		}
		JSONObject params = JSON.parseObject(responseStrBuilder.toString(), JSONObject.class);

		return params;
	}

}
